<template>
	<view>
		<view class='t-toptips' :style="{top: top,background: cubgColor}" :class="[show?'t-top-show':'']">
			<view v-if="loading" class="flex flex-sub">
				<view class="flex flex-sub">
					<view class="cu-progress flex-sub round striped active sm">
						<view :style="{ background: color,width: value + '%'}"></view>
					</view>
					<text class="margin-left">{{value}}%</text>
				</view>
				<view @click="downOnAbort" v-if="value<100" class="close">取消</view>
			</view>
			<block v-else>{{msg}}</block>
		</view>
		<!-- #ifdef H5 -->
		<h5-file 
		v-if="showH5"
		ref="h5File"
		:logo="logo"
		:showTip="showTip"
		:progress="value"
		@abort="onAbort"
		@close="onCloseH5"
		></h5-file>
		<!-- #endif -->
	</view>
</template>

<script>
import h5File from './h5-file.vue';
export default {
	components: {h5File},
	props: {
		logo: {
			type: String,
			default: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fbpic.588ku.com%2Felement_origin_min_pic%2F00%2F00%2F07%2F155788a6d8a5c42.jpg&refer=http%3A%2F%2Fbpic.588ku.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1619847627&t=2da40b583002205c204d980b54b35040'
		},
		top: {
			type: String,
			default: 'auto'
		},
		bgColor: {
			type: String,
			default: 'rgba(49, 126, 243, 0.5)',
		},
		color: {
			type: String,
			default: '#55aa00',
		}
	},
	data() {
		this.uploadTask = null;
		this.downloadTask = null;
		return {
			cubgColor: '',
			loading: false,
			value: 5,
			show: false,
			msg: '执行完毕~',
			showH5: false,
			showTip: false,
		}
	},
	methods: {
		toast(title = '',{ duration = 2000, icon = 'none'} = {}) {
			uni.showToast({title,duration,icon});
		},
		getRequest(url) {  
			let theRequest = new Object(); 
			let index = url.indexOf("?");
			if (index != -1) {  
				let str = url.substring(index+1);  
				let strs = str.split("&");  
				for(let i = 0; i < strs.length; i ++) {  
					theRequest[strs[i].split("=")[0]]=unescape(strs[i].split("=")[1]);  
				} 
			}  
			return theRequest;  
		},
		/*
			上传说明：
			currentWebview: 当前窗口webview对象
			url：上传接口地址
			name：上传文件key值
			header: 上传接口请求头
			...：body内其他参数
		*/
		appChooseFile({currentWebview,url,name = 'file',header,addName = '',addSize = '',maxSize = 10,...formData} = {}) {
			// #ifdef APP-PLUS
				let wvPath = '/uni_modules/l-file/hybrid/html/index.html';
				let wv = plus.webview.create("",wvPath,{
					'uni-app': 'none',
					top: 0,
					height: '100%',
					background: 'transparent'
				},{
					url,
					header,
					addName,
					addSize,
					maxSize,
					formData,
					key: name,
					logo: this.logo
				});
				wv.loadURL(wvPath);
				currentWebview.append(wv);
				wv.overrideUrlLoading({mode:'reject'},(e)=>{
					let {fileName,size,str} = this.getRequest(e.url);
					fileName = unescape(fileName);
					str = unescape(str);
					return this.handleBack(fileName,str,size);
				});
			// #endif
		},
		wxChooseFile({maxSize = 10,...param}) {
			wx.chooseMessageFile({
				count: 1,
				type: 'file',
				success: ({tempFiles}) => {
					this.setdefUI();
					let file = tempFiles[0];
					if(file.size > (1024*1024 * Math.abs(maxSize))) {
						uni.showToast({
							title:`单个文件请勿超过${maxSize}M,请重新上传`,
							icon: 'none'
						});
						return this.errorHandler('文件选择失败',this.upErr);
					}
					this.handleWXUpload(param,file);
				},
				fail: () => this.errorHandler('文件选择失败',this.upErr)
			})
		},
		h5ChooseFile({maxSize = 10,...param} = {}) {
			this.showH5 = true;
			this.value = 0;
			this.$nextTick(()=>{
				this.$refs.h5File.hFile.onchange = (event) => {  
					let file = event.target.files[0];
					if(file.size > (1024*1024 * Math.abs(maxSize))) {
						uni.showToast({
							title:`单个文件请勿超过${maxSize}M,请重新上传`,
							icon: 'none'
						});
						return;
					}
					this.handleH5Upload(param, file);
				}  
			})
		},
		handleH5Upload({url,name = 'file',header,addName,addSize,...data} = {},tempFile) {
			let fileName = tempFile.name;
			let formData = new FormData();
			for (let keys in data) {formData.append(keys, data[keys]);}
			if (addName) {formData.append(addName, fileName);}
			if (addSize) {formData.append(addSize, tempFile.size);}
			formData.append(name, tempFile);
			this.uploadTask = new XMLHttpRequest();
			this.uploadTask.open("POST", url, true);
			for (let keys in header) {this.uploadTask.setRequestHeader(keys, header[keys]);}
			
			this.uploadTask.ontimeout = () => {
				setTimeout(()=>{
					this.showTip = false;
					return this.errorHandler('请求超时',this.upErr);
				},1000);
			};
			
			this.uploadTask.upload.addEventListener("progress",(event) => {
				if(event.lengthComputable){
					this.value = Math.ceil(event.loaded * 100 / event.total);
					if (this.value > 100) {this.value=100;}
					this.$forceUpdate();
				}
			}, false);
			
			this.uploadTask.onreadystatechange = (ev) => {
				if(this.uploadTask.readyState == 4) {
					console.log('status：'+this.uploadTask.status);
					if (this.uploadTask.status == 200) {
						return this.handleBack(fileName,this.uploadTask.responseText,tempFile.size);
					}
					else {
						this.showTip = false;
						if (this.uploadTask.status == 0) {
							console.log('请检查请求头Content-Type与服务端是否匹配，并确认服务端已正确开启跨域');
						}
						return this.errorHandler('文件上传失败',this.upErr);
					}
					
				}
			};
			this.showTip = true;
			this.uploadTask.send(formData);
		},
		handleWXUpload({url,name = 'file',header,addName,addSize,...formData} = {},tempFile) {
			let opt = {url,name,formData,header,filePath:tempFile.path};
			if (addName) {opt.formData[addName] = tempFile.name;}
			if (addSize) {opt.formData[addSize] = tempFile.size;}
			let fileName = tempFile.name;
			opt['fail'] = (e) => {
				this.showTip = false;
				return this.errorHandler('文件上传失败',this.upErr)
			};
			opt['success'] = (res) => {
				if (res.statusCode==200) {
					let data = JSON.parse(res.data);
					//可自行添加后台返回状态验证
					return this.onCommit(this.$emit('up-success',{fileName,size:tempFile.size,data}));
				}
				return this.errorHandler('文件上传失败',this.upErr);
			};
			this.showTip = true;
			this.uploadTask = uni.uploadFile(opt);
			this.uploadTask&&this.uploadTask.onProgressUpdate(({progress = 0}) => {
				if (progress <= 100) {
					this.value = progress;
					this.$forceUpdate();
				}
			});
		},
		onCloseH5() {
			this.showH5 = false;
		},
		onAbort() {
			this.uploadTask&&this.uploadTask.abort();
			this.showTip = false;
		},
		downOnAbort() {
			this.downloadTask&&this.downloadTask.abort();
			this.onCommit(false,'已取消');
		},
		// app+h5返回内容，此处按实际项目修改
		handleBack(fileName,str = '{}',size) {
			console.log('可根据需求自行修改emit内容，服务端返回：'+ str);
			try{
				str = JSON.parse(str);
			}catch(e){
				console.log('Tips: responseText are not JSON');
			}
			return this.onCommit(this.$emit('up-success',{statusCode: 200,fileName,size,data:str}));
		},
		/* 
		上传
		*/
		upload(param = {}) {
			if (!param.url) {this.toast('上传地址不正确');return;}
			if (this.loading) {this.toast('还有个文件玩命处理中，请稍候..');return;}
			
			// #ifdef APP-PLUS
				return this.appChooseFile(param);
			// #endif
			
			// #ifdef MP-WEIXIN
				return this.wxChooseFile(param);
			// #endif
			
			// #ifdef H5
				this.h5ChooseFile(param);
			// #endif
		},
		/* 
		打开文件 
		*/
		open(filePath) {
			let system = uni.getSystemInfoSync().platform;
			if(system == 'ios'){filePath = encodeURI(filePath);}
			uni.openDocument({
				filePath,
				success: (res) => {console.log('打开文档成功');}
			});
		},
		/* 
		APP自定义保存 
		 */
		plusSaveFile({url,customName='',opt}) {
			return new Promise((resolve,reject)=>{
				// 可自行修改参数
				// 参数api: http://www.html5plus.org/doc/zh_cn/downloader.html#plus.downloader.DownloadOptions
				let downloadOptions = {
					method: "GET",
					timeout: 120,
					retryInterval: 10,
					filename:'file://storage/emulated/0/lFile/' + customName
				};
				downloadOptions = {...downloadOptions,...opt};
				this.downloadTask = plus.downloader.createDownload(url, downloadOptions,(d, status)=>{
					// 下载完成
					if(status == 200){ 
						let tempFilePath = d.filename;
						this.value = 100;
						this.onCommit(resolve(tempFilePath))
					} else {
						 this.errorHandler('下载失败',reject)
					}  
					this.downloadTask = null;
				});
				this.downloadTask.addEventListener('statechanged',({downloadedSize=0,state=0,totalSize=0}={})=>{
					if (state===3) {
						let total = totalSize>0?totalSize:fileSize;
						let progressVal = Math.ceil(downloadedSize / total* 100);
						this.value = progressVal>100?100:progressVal;
						this.$forceUpdate()
					}
				},false);
				this.downloadTask.start();
			});
		},
		/* 
		下载
		 type: temporary=返回临时地址，save=长期保存到本地
		 */
		download({url,type = 'temporary',customName = '',...opt}) {
			if (this.loading) {
				this.toast('还有个文件玩命处理中，请稍候..');
				return;
			}
			this.setdefUI();
			
			// #ifdef APP-PLUS
			if (type == 'save') {
				return this.plusSaveFile({url,customName,opt});
			}
			// #endif
			
			return new Promise((resolve,reject)=>{
				url = encodeURI(url);
				this.downloadTask = uni.downloadFile({
				    url,
					...opt,
				    success: ({statusCode,tempFilePath}) => {
				        if (statusCode === 200) {
							// #ifndef H5
							if (type == 'save') {
								uni.saveFile({
									tempFilePath,
									success:({savedFilePath}) => this.onCommit(resolve(savedFilePath)),
									fail: () => this.errorHandler('下载失败',reject)
								});
							}
							else {
								this.onCommit(resolve(tempFilePath))
							}
							// #endif
							
							// #ifdef H5
							this.onCommit(resolve(tempFilePath))
							// #endif
						}
					},
					fail: () => this.errorHandler('下载失败',reject)
				});
				
				this.downloadTask.onProgressUpdate(({progress = 0}) => {
					if (progress <= 100) {
						this.value = progress;
						this.$forceUpdate();
					}
				});
			})
			
		},
		
		onCommit(resolve,msg = '执行完毕~') {
			this.msg = msg;
			this.loading = false;
			this.showTip = false;
			this.cubgColor = 'rgba(57, 181, 74, 0.5)';
			this.uploadTask = null;
			this.downloadTask = null;
			setTimeout(()=>{this.show = false;this.showH5 = false;},1500);
			return resolve;
		},
		
		setdefUI() {
			this.cubgColor = this.bgColor;
			this.value = 0;
			this.loading = true;
			this.show = true;
		},
		
		upErr(errText) {
			this.$emit('up-error',errText);
		},
		
		errorHandler(errText,reject) {
			this.msg = errText;
			this.loading = false;
			this.cubgColor = 'rgba(229, 77, 66, 0.5)';
			this.uploadTask = null;
			this.downloadTask = null;
			setTimeout(()=>{this.show = false;},1500);
			return reject(errText);
		}
	}
}
</script>

<style scoped>
	.t-toptips {
		width: 100%;
		padding: 18upx 30upx;
		box-sizing: border-box;
		position: fixed;
		z-index: 90;
		color: #fff;
		font-size: 30upx;
		left: 0;
		display: flex;
		align-items: center;
		justify-content: center;
		word-break: break-all;
		opacity: 0;
		transform: translateZ(0) translateY(-100%);
		transition: all 0.3s ease-in-out;
	}
	
	.close {
		width: 3em;
		text-align: right;
	}
	
	.t-top-show {
		transform: translateZ(0) translateY(0);
		opacity: 1;
	}
	
	.flex {
		display: flex;
		align-items: center;
	}
	
	.flex-sub {
		flex: 1;
	}
	
	.round {
		border-radius: 5000upx;
	}
	
	/* ==================
	         进度条
	 ==================== */
	
	.cu-progress {
		overflow: hidden;
		height: 28upx;
		background-color: #ebeef5;
		display: inline-flex;
		align-items: center;
		width: 100%;
	}
	
	.cu-progress+view,
	.cu-progress+text {
		line-height: 1;
	}
	
	.cu-progress.xs {
		height: 10upx;
	}
	
	.cu-progress.sm {
		height: 20upx;
	}
	
	.cu-progress view {
		width: 0;
		height: 100%;
		align-items: center;
		display: flex;
		justify-items: flex-end;
		justify-content: space-around;
		font-size: 20upx;
		color: #ffffff;
		transition: width 0.6s ease;
	}
	
	.cu-progress text {
		align-items: center;
		display: flex;
		font-size: 20upx;
		color: #333333;
		text-indent: 10upx;
	}
	
	.cu-progress.text-progress {
		padding-right: 60upx;
	}
	
	.cu-progress.striped view {
		background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
		background-size: 72upx 72upx;
	}
	
	.cu-progress.active view {
		animation: progress-stripes 2s linear infinite;
	}
	
	@keyframes progress-stripes {
		from {
			background-position: 72upx 0;
		}
	
		to {
			background-position: 0 0;
		}
	}
	
</style>
